
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QClipboard>
#include <QDebug>
#include <QFileDialog>
#include <QFileInfoList>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QProcess>
#include <QTimer>
#include <checkoutdialog.h>
#include <config.h>
#include <dbusutil.h>
#include <gitutil.h>
#include <qd.h>
#include <others/gitlogpreviewwidget.h>
#include <reposelfupdatedialog.h>
#include <repoutil.h>
#include <settingsdialog.h>
#include <sloverevisionnotfounddialog.h>

#include <configutil.h>
#include <repoanalyzermanager.h>
#include <moveeater.h>
#include <overlayfssettingsdialog.h>
#include <tablewidgetutil.h>
#include <linuxterminalhelper.h>

#define COL_NAME 0 // 项目名称
#define COL_PATH 1 // 检出位置
#define COL_CHEK 2 // 是否已检出
#define COL_SLOV 3 // 解决方案
#define COL_REMT 4 // 远程仓库
#define COL_REVI 5 // 修订版本

#define ACTION_VARS()                                                                           \
    QString workdir = ui->repo_dir_path_input->text();                                           \
    if (!RepoUtil::isVerify(workdir)) {                                                         \
        return;                                                                                 \
    }                                                                                           \
                                                                                                \
    Columns column = table_widget_item_columns_at_row(ui->projectTableWidget->currentItem());   \
    auto row       = column.row;                                                                \
    auto name      = column.name;                                                               \
    auto path      = column.path;                                                               \
    auto realpath  = column.solution_path;                                                      \
                                                                                                \
    QList<Columns> columns = table_widget_item_columns_at_rows();                               \
    QStringList names;                                                                          \
    QStringList paths;                                                                          \
    foreach (auto var, columns) {                                                               \
        names << var.name;                                                                      \
        paths << var.path;                                                                      \
    }                                                                                           \


MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , action_git_reset(new QAction("仓库硬重置"))
    , action_delete_index_lock(new QAction("解除锁"))
{
    ui->setupUi(this);
    ui->projectTableWidget->sortByColumn(COL_NAME, Qt::AscendingOrder);
    // ui->projectTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Stretch);
    ui->projectTableWidget->setSelectionMode(QAbstractItemView::SelectionMode::ExtendedSelection);;
    ui->projectTableWidget->horizontalHeader()->setStretchLastSection(true);
    ui->projectTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
    ui->projectTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);

    // [] 创建 tooltip 形式控件
    auto git_log_tooltip = new GitLogPreviewWidget(this);
    // 1. 该控件需要一个实例
    git_log_tooltip->setInstance(ui->projectTableWidget);
    // 2. 该控件需要一个回调
    git_log_tooltip->setColumnsFunc([this](QTableWidgetItem *item) -> Columns {
        return table_widget_item_columns_at_row(item);
    });
    // 3. 该控件依赖一些事件如: 鼠标在表格中激活单元格 tooltip 与悬浮移动时。
    ui->projectTableWidget->viewport()->installEventFilter(git_log_tooltip);


    on_tabWidget_currentChanged(0);

    if (ConfigUtil::getAppRepoConfig().isEmpty())
    {
        ui->statusbar->showMessage("提示：未配置 repo 路径");
    }
    else
    {
        ui->statusbar->showMessage("已配置路径: " + ConfigUtil::getAppRepoConfig());
    }

    new MoveEater(this, this);

    repo_manager = new RepoAnalyzerManager;
    connect(repo_manager, &RepoAnalyzerManager::notify_solution, this, [this](const QString &path, const QString &solution, bool manual){

        qd << manual;
        for (int i = 0; i < cache.project_size(); ++i) {
            auto item = ui->projectTableWidget->item(i, COL_PATH);
            if (item && item->text() == path) {

                ui->projectTableWidget->item(i, COL_SLOV)->setText(solution);

                if (manual) { // 手动触发时查询时检查检出状态
                    auto checked_text = RepoUtil::query_path_is_checked(cache.workdir(), path);
                    ui->projectTableWidget->item(i, COL_CHEK)->setText(checked_text);
                    if (checked_text == "已检出")
                        cache.increment_verify_count();

                } else { // 自动化期间进行正常计数
                    if (solution != "正常")
                        cache.increment_solution_count();
                }
                break;
            }
        }

        if (!manual)
            ui->progressbar_loading->setValue(ui->progressbar_loading->value()+1);
        ui->verify_project_count->setText(QString::number(cache.verifyCount()));
        ui->verify_solution_count->setText(QString::number(cache.solutionCount()));
    });
    repo_manager->start();

    emit repo_manager->applySettings();

    { // 内置动作
        connect(action_git_reset, &QAction::triggered, this,[this](){
            ACTION_VARS()

            if (columns.count() == 1) {
                qd << "reset:" << path;
                if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将重置:\n" + path + "目录")) {
                    // RepoUtil::repo_project_objects_name_objects_pack_clean_tmp_pack_file(workdir, name);
                    GitUtil::git_reset(RepoUtil::_paths(workdir, path), true);
                    emit repo_manager->solution(workdir, name, path);
                }
            } else {
                if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将在'"+workdir+"'中重置以下目录:\n" + paths.join("\n"))) {
                    for (int i = 0; i < columns.count(); ++i) {
                        // RepoUtil::repo_project_objects_name_objects_pack_clean_tmp_pack_file(workdir, names.at(i));
                        GitUtil::git_reset(RepoUtil::_paths(workdir, paths[i]), true);
                        emit repo_manager->solution(workdir, names[i], paths[i]);
                    }
                }
            }
        });

        connect(action_delete_index_lock, &QAction::triggered, this,[this](){
            ACTION_VARS()

            if (columns.count() == 1) {
                qd << "rm index.lock:" << path;
                if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将解锁:\n" + path + "目录")) {
                    // RepoUtil::repo_project_objects_name_objects_pack_clean_tmp_pack_file(workdir, name);
                    QFile(RepoUtil::_paths(workdir, path, ".git", "index.lock")).remove();
                    emit repo_manager->solution(workdir, name, path);
                }
            } else {
                if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将在'"+workdir+"'中解锁以下目录:\n" + paths.join("\n"))) {
                    for (int i = 0; i < columns.count(); ++i) {
                        // RepoUtil::repo_project_objects_name_objects_pack_clean_tmp_pack_file(workdir, names.at(i));
                        QFile(RepoUtil::_paths(workdir, paths[i], ".git", "index.lock")).remove();
                        emit repo_manager->solution(workdir, names[i], paths[i]);
                    }
                }
            }
        });
    }


    // actions
    // [ ] 复制路径
    action_copy_path = new MenuTriggerAction("复制路径");
    action_copy_path->setTableWidgetCallback(ui->projectTableWidget, [this](auto item){
        auto column = table_widget_item_columns_at_row(item);
        qd << "copy path:" << column.realpath;
        qApp->clipboard()->setText(column.realpath);
    });

    // [ ] xdg-open 打开所在目录
    action_xdgopen_dir = new MenuTriggerAction("打开所在目录");
    action_xdgopen_dir->setTableWidgetCallback(ui->projectTableWidget, [this](auto item){
        auto column = table_widget_item_columns_at_row(item);
        qd << "opendir:" << column.realpath;
        DBusUtil::showFileLocation(column.realpath);
    });

    // [ ] 使用 VSCode 打开选中项
    action_vscode_open = new MenuTriggerAction("使用 vscode 打开");
    action_vscode_open->setTableWidgetCallback(ui->projectTableWidget, [this](auto item){
        auto column = table_widget_item_columns_at_row(item);
        auto columns = table_widget_item_columns_at_rows();

        if (columns.count() > 1) {
            auto paths = map(columns, [](const Columns &columns){ return columns.path; });
            auto realpaths = map(columns, [](const Columns &columns){ return columns.realpath; });
            if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将在 VSCode 中打开以下目录:\n" + paths.join("\n"))) {
                qd << "code:" << realpaths;
                QProcess::startDetached("code", realpaths);
            }
        } else {
            qd << "code:" << column.realpath;
            QProcess::startDetached("code", QStringList(column.realpath));
        }
    });

#ifdef Q_OS_LINUX
    auto linux_terminal = LinuxTerminalHelper::isTerminalSupported();
    if (linux_terminal.first) {
        action_linux_terminal_open = new MenuTriggerAction(QString("在终端 '%1' 中打开").arg(linux_terminal.second.name));
        action_linux_terminal_open->setTableWidgetCallback(ui->projectTableWidget, [this](auto item){
            auto ok = LinuxTerminalHelper::isTerminalSupported();
            auto column = table_widget_item_columns_at_row(item);
            qd << ok.second.command + ":" << column.realpath;
            LinuxTerminalHelper::openTerminalHere(column.realpath);
        });
    }
#endif

    // [ ] 在 vscode 中打开 manifests 清单项目
    action_vscode_open_manifests = new MenuTriggerAction("");
    action_vscode_open_manifests->setSimpleCallback([this](){
        QString workdir = ui->repo_dir_path_input->text();
        if (!RepoUtil::isVerify(workdir)) {
            return;
        }
        auto realpath = workdir + QDir::separator() + ".repo/manifests";
        QProcess::startDetached("code", QStringList(realpath));
    });
}
MainWindow::~MainWindow()
{
    delete ui;
}

/**
 * @brief item 的 Columns 信息
 * @param item
 * @return
 */
Columns MainWindow::table_widget_item_columns_at_row(const QTableWidgetItem *item)
{
    int row;
    if (item) {
        row = item->row();
    } else {
        row = ui->projectTableWidget->currentItem()->row();
    }
    auto name = ui->projectTableWidget->item(row, COL_NAME)->text();
    auto path = ui->projectTableWidget->item(row, COL_PATH)->text();
    auto realpath = ui->projectTableWidget->item(row, COL_PATH)->data(Qt::UserRole).toString();
    auto checkouted = ui->projectTableWidget->item(row, COL_CHEK)->text() == "已检出";
    auto checkouted_text = ui->projectTableWidget->item(row, COL_CHEK)->text();
    auto solution = ui->projectTableWidget->item(row, COL_SLOV)->text() == "正常";
    auto solution_text = ui->projectTableWidget->item(row, COL_SLOV)->text();
    auto solution_path = ui->projectTableWidget->item(row, COL_SLOV)->data(Qt::UserRole).toString();
    auto remote = ui->projectTableWidget->item(row, COL_REMT)->text();
    auto revision = ui->projectTableWidget->item(row, COL_REVI)->text();

    return Columns {
        row,            // 行
        name, path, realpath, // 名称，路径, 用户数据(实际路径)
        checkouted, checkouted_text, // 是否检出，
        solution, solution_text, solution_path, // 解决方案
        remote, revision, // 远程仓库，修订版本
    };
}

QList<Columns> MainWindow::table_widget_item_columns_at_rows()
{
    QList<Columns> unique_columns;
    auto selects = ui->projectTableWidget->selectedItems();

    QList<int> unique_rows;
    foreach (auto var, ui->projectTableWidget->selectedItems()) {
        if (unique_rows.contains(var->row())) {
            continue;
        }
        unique_rows << var->row();
        unique_columns << table_widget_item_columns_at_row(var);
    }

    return unique_columns;
}

QTableWidgetItem *MainWindow::createQTableWidgetItem(const QString display, const QString &userData)
{
    QTableWidgetItem *item = new QTableWidgetItem();
    item->setText(display);
    item->setData(Qt::UserRole, userData);
    // changed: 不需要，会影响自定义的 log 预览
    // item->setToolTip(display);
    return item;
}

QTableWidgetItem *MainWindow::createProjectNameQTableWidgetItem(const QString &dir, const QString &name)
{
    return createQTableWidgetItem(name);
}

QTableWidgetItem *MainWindow::createPathQTableWidgetItem(const QString &dir, const QString &path)
{
    return createQTableWidgetItem(path, dir + QDir::separator() + path);
}

QTableWidgetItem *MainWindow::createCheckedQTableWidgetItem(const QString &dir, const QString &path)
{
    return createQTableWidgetItem(RepoUtil::query_path_is_checked(dir, path));
}

QTableWidgetItem *MainWindow::createSolutionQTableWidgetItem(const QString &dir, const QString &name, const QString &path)
{
    QString realpath = dir + QDir::separator() + ".repo/project-objects/" + name + ".git";
    return createQTableWidgetItem("分析中...", realpath);
}

QTableWidgetItem *MainWindow::createRemoteQTableWidgetItem(const QString &dir, const QString &name, const QString &path, const QVariantMap &var)
{
    Q_UNUSED(name)
    Q_UNUSED(path)

    QTableWidgetItem *item;

    if (var.contains("remote")) {
        item = createQTableWidgetItem(var.value("remote").toString());
    } else {
        item = createQTableWidgetItem(cache.remote());
    }

    return item;
}

/**
 * @brief MainWindow::createRevisionQTableWidgetItem
 * @param dir
 * @param name
 * @param path
 * @param var
 * @return
 */
QTableWidgetItem *MainWindow::createRevisionQTableWidgetItem(const QString &dir, const QString &name, const QString &path, const QVariantMap &var)
{
    Q_UNUSED(name)
    Q_UNUSED(path)

    QTableWidgetItem *item;

    if (var.contains("revision")) {
        item = createQTableWidgetItem(var.value("revision").toString());
    } else {
        item = createQTableWidgetItem(cache.revision());
    }

    if (var.contains("remote")) {
        item->setData(Qt::UserRole, var.value("remote").toString());
    } else {
        item->setData(Qt::UserRole, cache.remote());
    }

    return item;
}

void MainWindow::loaderProjects()
{
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    cache.setWorkdir(workdir);
    cache.setRemote(RepoUtil::default_remote(workdir));
    cache.setRevision(RepoUtil::default_revision(workdir));

    cache.setRemotes(RepoUtil::remote(workdir));
    cache.setProjects(RepoUtil::project(workdir));

    ui->branch->setText(RepoUtil::manifest_branch(workdir).b);
    ui->remote->setText(cache.remote());
    ui->revision->setText(cache.revision());
    ui->projectCount->setText(QString::number(cache.project_size()));

    auto project = cache.projects();

    cache.reset_verify_solution_count();
    ui->progressbar_loading->setValue(0);
    ui->progressbar_loading->setMaximum(project.size());
    ui->projectTableWidget->setRowCount(project.size());

    for (int i = 0; i < project.size(); ++i) {
        auto var = project.at(i).toMap();
        if (var.contains("name")) {
            QString name = var.value("name").toString();
            QString path = var.value("path").toString();

            if (path.isEmpty()) {
                path = name;
            }

            QTableWidgetItem *itemName = createProjectNameQTableWidgetItem(workdir, name);
            ui->projectTableWidget->setItem(i ,COL_NAME, itemName);

            QTableWidgetItem *itemPath = createPathQTableWidgetItem(workdir, path);
            ui->projectTableWidget->setItem(i ,COL_PATH, itemPath);

            QTableWidgetItem *itemChecked = createCheckedQTableWidgetItem(workdir, path);
            ui->projectTableWidget->setItem(i, COL_CHEK, itemChecked);

            QTableWidgetItem *itemSolution = createSolutionQTableWidgetItem(workdir, name, path);
            ui->projectTableWidget->setItem(i, COL_SLOV, itemSolution);

            QTableWidgetItem *itemRemote = createRemoteQTableWidgetItem(workdir, name, path, var);
            ui->projectTableWidget->setItem(i, COL_REMT, itemRemote);

            QTableWidgetItem *itemRevision = createRevisionQTableWidgetItem(workdir, name, path, var);
            ui->projectTableWidget->setItem(i, COL_REVI, itemRevision);

            if (itemChecked->text() == "已检出") cache.increment_verify_count();
            emit repo_manager->commit_fast_solution(workdir, name, path);
        }
    }

    QTimer::singleShot(300, repo_manager, &RepoAnalyzerManager::start_fast_solution);
}

void MainWindow::loaderManifests()
{
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        ui->projectManifestTextBrowser->clear();
        return;
    }

    if (ui->projectManifestJson->isChecked()) {
        QJsonDocument document = QJsonDocument::fromJson(RepoUtil::manifest_json_str(workdir).toUtf8());
        if (document.isEmpty()) {
            return;
        }
        QString json = document.toJson();
        ui->projectManifestTextBrowser->setText(json);
    } else {
        ui->projectManifestTextBrowser->setText(RepoUtil::manifest(workdir));
    }
}

void MainWindow::load(const QString &dir)
{
    // QTimer::singleShot(1000, [this, dir](){
    //     ui->repo_dir_path_input->setText(QDir(dir).absolutePath());
    // });
    QMetaObject::invokeMethod(ui->repo_dir_path_input, "setText",
                              Q_ARG(const QString, QDir(dir).absolutePath()));
}

void MainWindow::on_chooseRepoDir_clicked()
{
    QString existingDirectory = QFileDialog::getExistingDirectory(this, QString(), ui->repo_dir_path_input->text(), QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly);
    if (existingDirectory.isEmpty()) return;

    ui->repo_dir_path_input->setText(existingDirectory);
}

void MainWindow::on_repo_dir_path_input_textChanged(const QString &dirPath)
{
    ui->projectTableWidget->clearContents();
    ui->projectTableWidget->setSortingEnabled(false);   // 关闭排序

    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        ui->projectManifestTextBrowser->clear();
        ui->projectCount->setText("...");
        ui->revision->setText("...");
        ui->status->setText("错误的 repo 仓库路径");
        ui->repo_dir_path_input->setStyleSheet("QLineEdit { color: red; }");
        ui->projectTableWidget->setRowCount(0);
        return;
    }

    ui->repo_dir_path_input->setStyleSheet("");
    ui->status->setText("有效的 repo 仓库路径");

    loaderProjects();
    loaderManifests();

    ui->projectTableWidget->setSortingEnabled(true);    // 开启排序
    ui->repo_dir_path_input->disconnect();
    ui->repo_dir_path_input->setText(workdir);
    connect(ui->repo_dir_path_input, &QLineEdit::textChanged, this, &MainWindow::on_repo_dir_path_input_textChanged);

    ui->projectTableWidget->horizontalHeader()->resizeSections(QHeaderView::Stretch);
}

void MainWindow::on_reload_clicked()
{
    on_repo_dir_path_input_textChanged(ui->repo_dir_path_input->text());
}

void MainWindow::on_projectTableWidget_itemSelectionChanged()
{
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }
    update_select_item_status(workdir);
}

void MainWindow::on_projectManifestJson_stateChanged(int arg1)
{
    loaderManifests();
}

void MainWindow::on_tabWidget_currentChanged(int index)
{
    //
    ui->btn_copy_project_names->setHidden(true);
    ui->projectManifestJson->setHidden(true);

    switch(index) {
    case 0:
        ui->btn_copy_project_names->setHidden(false);
        break;
    case 1:
        ui->projectManifestJson->setHidden(false);
        break;
    }
}

void MainWindow::on_btn_copy_project_names_clicked()
{
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        ui->projectManifestTextBrowser->clear();
        return;
    }

    QClipboard *clipboard = QApplication::clipboard();
    clipboard->setText(RepoUtil::project_names(workdir).join("\n"));
    ui->status->setText(QString("已复制: %1 项").arg(RepoUtil::project_names(workdir).count()));
}

/**
 * @brief 设置 repo 工具路径
 */
void MainWindow::on_action_repo_triggered()
{
    // curl https://mirrors.bfsu.edu.cn/git/git-repo -o repo
    QString filename = QFileDialog::getOpenFileName(nullptr, "", "", "repo repo.py");
    if (filename.isEmpty() == false)
    {
        ConfigUtil::setAppRepoConfig(filename);
        ui->statusbar->showMessage("已配置路径: " + filename);
    }
}

/**
 * @brief 选中项更新检出状态
 * @param workdir
 */
void MainWindow::update_select_item_status(const QString &workdir)
{
    int row = ui->projectTableWidget->currentIndex().row();
    QTableWidgetItem *item = ui->projectTableWidget->item(row, COL_PATH);
    if (item == nullptr) return;

    QString path = workdir + "/" + item->text();

    if (!QFileInfo::exists(path)) {
        ui->status->setText("项目(未检出): " + item->text());
        return;
    }
    ui->status->setText("项目(已检出): " + item->text());
}

void MainWindow::on_projectTableWidget_customContextMenuRequested(const QPoint &pos)
{
    QMenu menu;
    // [1] 当没有选中元素时退出
    if (!ui->projectTableWidget->currentItem()) {
        return;
    }

    // [2] 获取工作目录
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    Columns column = table_widget_item_columns_at_row(ui->projectTableWidget->currentItem());
    auto row        = column.row;
    auto name       = column.name;
    auto path       = column.path;
    auto checkouted = column.checkeouted;
    auto solution   = column.solution;
    auto solution_text = column.solution_text;
    auto remote     = column.remote;
    auto revision   = column.revision;

    QList<Columns> columns = table_widget_item_columns_at_rows();
    QStringList names;
    QStringList paths;
    QStringList realpaths;
    foreach (auto var, columns) {
        names << var.name;
        paths << var.path;
    }

    // 1. 检出操作
    if (columns.count() == 1) {
        menu.addAction("检出", [this, workdir, name, path](){
            qd << "检出";
            CheckoutDialog dialog;
            dialog.setWindowTitle("repo 正在检出：" + path);
            dialog.setWorkdir(workdir);
            dialog.setPath(path);
            dialog.start();
            dialog.exec();
            emit repo_manager->solution(workdir, name, path);
        })->setEnabled(!checkouted);
    } else {
        menu.addAction("检出所有选中", [this, workdir, names, paths, columns](){
            qd << "检出所有选中";
            CheckoutDialog dialog;
            dialog.setWindowTitle("repo 正在检出选中");
            dialog.setWorkdir(ui->repo_dir_path_input->text());
            dialog.setPaths(paths);
            dialog.start();
            dialog.exec();
            for (int i = 0; i < columns.count(); ++i) {
                emit repo_manager->solution(workdir, names[i], paths[i]);
            }
        });
    }

    // 2. 打开所在目录
    menu.addAction(action_copy_path);
    menu.addAction(action_xdgopen_dir);

    // 3. 使用...打开
    {
        auto open_menu = menu.addMenu("使用...打开");
        open_menu->addAction(action_vscode_open);
#ifdef Q_OS_LINUX
        if (LinuxTerminalHelper::isTerminalSupported().first) {
            open_menu->addAction(action_linux_terminal_open);
        }
#endif
    }

    // 4. 解决方案
    {
        auto solution_menu = menu.addMenu("解决方案");
        solution_menu->addAction(ui->action_solution_incomplete);
        {// 缺失该对象
            ui->action_solution_incomplete->setEnabled(solution_text.contains("缺失"));
        }
        solution_menu->addAction(ui->action_solution_file_lose_weight);
        {// 可瘦身
            ui->action_solution_file_lose_weight->setEnabled(solution_text.contains("瘦身"));
        }

        // Solve 'revision not found'
        {
            auto solve_revision_menu = solution_menu->addMenu("Solve 'revision not found'");
            solve_revision_menu->addAction(ui->action_solution_solve_revision_not_found_fetch_missing_revision);
            solve_revision_menu->addAction(ui->action_solution_solve_revision_not_found_delete_and_resynchronize);
            {// Slove "revision not found"
                ui->action_solution_solve_revision_not_found_fetch_missing_revision->setEnabled(solution_text.contains("revision not found"));
                ui->action_solution_solve_revision_not_found_delete_and_resynchronize->setEnabled(solution_text.contains("revision not found"));
            }
        }

        {// git workspace
            auto solve_git_workspace = solution_menu->addMenu("Git Workspace");
            solve_git_workspace->addAction(ui->action_solution_slove_git_workspace_git_init_and_resynchronization);
            {// 空项目
                ui->action_solution_slove_git_workspace_git_init_and_resynchronization->setEnabled(solution_text.contains("空项目"));
            }
            solve_git_workspace->addAction(action_git_reset);
            {// 已修改
                action_git_reset->setEnabled(solution_text.contains("已修改"));
            }
            solve_git_workspace->addAction(action_delete_index_lock);
            {// 存在锁
                action_delete_index_lock->setEnabled(solution_text.contains("存在锁"));
            }
        }

        solution_menu->setEnabled(!solution);
    }

    menu.exec(QCursor::pos());
}

/**
 * @brief 在 vscode 中打开 manifests 清单项目
 */
void MainWindow::on_action_vscode_open_manifests_triggered()
{
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    auto realpath = workdir + QDir::separator() + ".repo/manifests";

    QProcess::startDetached("code", QStringList(realpath));
}

/**
 * @brief 仓库不完整性处理
 */
void MainWindow::on_action_solution_incomplete_triggered()
{
    if (!ui->projectTableWidget->currentItem()) {
        return;
    }
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    Columns column = table_widget_item_columns_at_row(ui->projectTableWidget->currentItem());
    auto row        = column.row;
    auto name       = column.name;
    auto path       = column.path;
    auto checkouted = column.checkeouted;
    auto solution   = column.solution;
    auto solution_text = column.solution_text;
    auto realpath   = column.solution_path;
    auto remote     = column.remote;
    auto revision   = column.revision;

    QList<Columns> columns = table_widget_item_columns_at_rows();
    QStringList names;
    QStringList paths;
    QStringList realpaths;
    foreach (auto var, columns) {
        names << var.name;
        paths << var.path;
        realpaths << var.solution_path;
    }
    if (columns.count() == 1) {
        qd << "incomplete:" << realpath;
        if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将移除:\n" + realpath + "目录")) {
            QDir dir(realpath);
            qd << "执行删除操作:" << dir.removeRecursively();
            CheckoutDialog dialog;
            dialog.setWindowTitle("repo 正在检出：" + path);
            dialog.setWorkdir(workdir);
            dialog.setPath(path);
            dialog.start();
            dialog.exec();
            emit repo_manager->solution(workdir, name, path);
        }
    } else {
        qd << "incompletes:" << realpaths;
        if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将在'"+workdir+"'中移除以下目录:\n" + paths.join("\n"))) {
            for (int i = 0; i < columns.count(); ++i) {
                QDir dir(realpaths.at(i));
                qd << "执行删除操作:" << paths.at(i) << dir.removeRecursively();
            }
            CheckoutDialog dialog;
            dialog.setWindowTitle("repo 正在检出：" + path);
            dialog.setWorkdir(workdir);
            dialog.setPaths(paths);
            dialog.start();
            dialog.exec();
            for (int i = 0; i < columns.count(); ++i) {
                emit repo_manager->solution(workdir, names[i], paths[i]);
            }
        }
    }
}

/**
 * @brief revision not found 解决方案(尝试拉取 revision)
 */
void MainWindow::on_action_solution_solve_revision_not_found_fetch_missing_revision_triggered()
{
    qd;
    if (!ui->projectTableWidget->currentItem()) {
        return;
    }
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    Columns column = table_widget_item_columns_at_row(ui->projectTableWidget->currentItem());
    auto row       = column.row;
    auto name      = column.name;
    auto path      = column.path;
    auto remote    = column.remote;
    auto revision  = column.revision;

    QList<Columns> columns = table_widget_item_columns_at_rows();
    QStringList names;
    QStringList paths;
    foreach (auto var, columns) {
        names << var.name;
        paths << var.path;
    }

    if (columns.count() == 1) {
        qd << "fetch revision:" << revision;
        if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将处理以下:\n" + QString("1.项目名称: %1\n2.检出位置: %2\n3.远程仓库: %3\n4.修订版本: %4").arg(name).arg(path).arg(remote).arg(revision))) {
            RepoUtil::repo_info_validate_slove_revision_not_found_fetch_missing_revision(workdir, name, path);
            SloveRevisionNotFoundDialog dialog;
            dialog.setWindowTitle("正在拉取：" + revision);
            dialog.setWorkdir(workdir);
            dialog.setPath(path);
            dialog.setRemote(remote);
            dialog.setRevision(revision);
            dialog.start();
            dialog.exec();
            emit repo_manager->solution(workdir, name, path);
        }
    }
}

/**
 * @brief revision not found 解决方案(删除 3 个目录目录)
 */
void MainWindow::on_action_solution_solve_revision_not_found_delete_and_resynchronize_triggered()
{
    qd;
    if (!ui->projectTableWidget->currentItem()) {
        return;
    }
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    Columns column = table_widget_item_columns_at_row(ui->projectTableWidget->currentItem());
    auto row       = column.row;
    auto name      = column.name;
    auto path      = column.path;
    auto realpath  = column.solution_path;
    auto remote    = column.remote;
    auto revision  = column.revision;

    QList<Columns> columns = table_widget_item_columns_at_rows();
    QStringList names;
    QStringList paths;
    foreach (auto var, columns) {
        names << var.name;
        paths << var.path;
    }

    if (columns.count() == 1) {
        qd << "incomplete:" << realpath;
        if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将移除以下目录:\n" + QString("1.项目名称: %1\n2.检出位置: %2").arg(name).arg(path))) {
            RepoUtil::repo_info_validate_slove_revision_not_found_delete_and_resynchronize(workdir, name, path);
            CheckoutDialog dialog;
            dialog.setWindowTitle("repo 正在检出：" + path);
            dialog.setWorkdir(workdir);
            dialog.setPath(path);
            dialog.start();
            dialog.exec();
            emit repo_manager->solution(workdir, name, path);
        }
    }
}

/**
 * @brief 解决方案(瘦身处理)
 */
void MainWindow::on_action_solution_file_lose_weight_triggered()
{
    qd;
    if (!ui->projectTableWidget->currentItem()) {
        return;
    }
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    Columns column = table_widget_item_columns_at_row(ui->projectTableWidget->currentItem());
    auto row       = column.row;
    auto name      = column.name;
    auto path      = column.path;
    auto realpath  = column.solution_path;

    QList<Columns> columns = table_widget_item_columns_at_rows();
    QStringList names;
    QStringList paths;
    foreach (auto var, columns) {
        names << var.name;
        paths << var.path;
    }

    if (columns.count() == 1) {
        qd << "lose weight:" << name;
        if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将瘦身:\n" + realpath + "目录")) {
            RepoUtil::repo_project_objects_name_objects_pack_clean_tmp_pack_file(workdir, name);
            emit repo_manager->solution(workdir, name, path);
        }
    } else {
        if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将在'"+workdir+"'中瘦身以下目录:\n" + paths.join("\n"))) {
            for (int i = 0; i < columns.count(); ++i) {
                RepoUtil::repo_project_objects_name_objects_pack_clean_tmp_pack_file(workdir, names.at(i));
                emit repo_manager->solution(workdir, names[i], paths[i]);
            }
        }
    }
}

/**
 * @brief 工作区异常
 */
void MainWindow::on_action_solution_slove_git_workspace_git_init_and_resynchronization_triggered()
{
    qd;
    if (!ui->projectTableWidget->currentItem()) {
        return;
    }
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    Columns column = table_widget_item_columns_at_row(ui->projectTableWidget->currentItem());
    auto row       = column.row;
    auto name      = column.name;
    auto path      = column.path;
    auto realpath  = column.solution_path;

    QList<Columns> columns = table_widget_item_columns_at_rows();
    QStringList names;
    QStringList paths;
    foreach (auto var, columns) {
        names << var.name;
        paths << var.path;
    }

    if (columns.count() == 1) {
        qd << "no files:" << name;
        if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将初始化:\n" + realpath + "目录")) {
            RepoUtil::git_workspace_init(workdir, path);
            CheckoutDialog dialog;
            dialog.setWindowTitle("repo 正在检出：" + path);
            dialog.setWorkdir(workdir);
            dialog.setPath(path);
            dialog.start();
            dialog.exec();
            emit repo_manager->solution(workdir, name, path);
        }
    } else {
        qd << "no files:" << names;
        if (QMessageBox::Yes == QMessageBox::question(this, "确认操作?", "即将在'"+workdir+"'中初始化以下目录:\n" + paths.join("\n"))) {
            for (int i = 0; i < columns.count(); ++i) {
                RepoUtil::git_workspace_init(workdir, paths[i]);
            }
            CheckoutDialog dialog;
            dialog.setWindowTitle("repo 正在检出：" + path);
            dialog.setWorkdir(workdir);
            dialog.setPaths(paths);
            dialog.start();
            dialog.exec();
            for (int i = 0; i < columns.count(); ++i) {
                emit repo_manager->solution(workdir, names[i], paths[i]);
            }
        }
    }
}

/**
 * @brief 本体更新
 */
void MainWindow::on_action_repo_repo_git_pull_triggered()
{
    qd;
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    RepoSelfUpdateDialog dialog;
    dialog.setWindowTitle("repo 本体更新");
    dialog.setWorkdir(workdir);
    dialog.start();
    dialog.exec();
}

void MainWindow::on_action_overlayfs_dialog_triggered()
{
    OverlayfsSettingsDialog dialog;
    dialog.exec();
}

/**
 * @brief 全量同步
 */
void MainWindow::on_action_repo_sync_full_synchronization_triggered()
{
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    auto realpath = workdir + QDir::separator() + ".repo/manifests";
    CheckoutDialog dialog;
    dialog.setWindowTitle("repo sync 全量同步");
    dialog.setWorkdir(workdir);
    dialog.setType(CheckoutDialog::Sync);
    dialog.start();
    dialog.exec();
    on_reload_clicked();
}

void MainWindow::on_action_repo_sync_detach_full_synchronization_triggered()
{
    QString workdir = ui->repo_dir_path_input->text();
    if (!RepoUtil::isVerify(workdir)) {
        return;
    }

    auto realpath = workdir + QDir::separator() + ".repo/manifests";
    CheckoutDialog dialog;
    dialog.setWindowTitle("repo sync 全量同步(detach)");
    dialog.setWorkdir(workdir);
    dialog.setType(CheckoutDialog::SyncDetach);
    dialog.start();
    dialog.exec();
    on_reload_clicked();
}


void MainWindow::table_view_vision_adjust()
{
    ui->projectTableWidget->horizontalHeader()->resizeSections(QHeaderView::Stretch);
    ui->projectTableWidget->resizeColumnToContents(COL_CHEK);
    ui->projectTableWidget->resizeColumnToContents(COL_SLOV);
    ui->projectTableWidget->resizeColumnToContents(COL_REMT);
    ui->projectTableWidget->resizeColumnToContents(COL_REVI);
}

void MainWindow::on_edit_filter_textChanged(const QString &arg1)
{
    if (arg1.isEmpty()) {
        TableWidgetUtil::show_all(ui->projectTableWidget);
        return;
    }

    TableWidgetUtil::show_all(ui->projectTableWidget, false);
    foreach (auto item, ui->projectTableWidget->findItems(arg1, Qt::MatchContains)) {
        ui->projectTableWidget->showRow(item->row());
    }

    table_view_vision_adjust();
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);

    table_view_vision_adjust();
}

void MainWindow::on_action_open_settings_dialog_triggered()
{
    SettingsDialog dialog;
    if (dialog.exec() == QDialog::Accepted) {
        emit repo_manager->applySettings();
    }
}
